Skip to content
main
Switch branches/tags
jam0001/BenJilks/
jam0001/BenJilks/

Latest commit

Co-authored-by: BenJilks <benjyjilks@gmail.com>
174285e

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
Aug 20, 2021

Name: BenJilks Date: Sunday the 22nd of August 2021 Mood: good

Readme

     _____ ____ ____  _     ___ _______         __
    |_   _/ ___|  _ \| |   |_ _|_   _\ \   _   / /
      | || |  _| |_) | |    | |  | |  \ \ / \ / / 
      | || |_| |  __/| |___ | |  | |   \ V _ V /  
      |_| \____|_|   |_____|___| |_|    \_/ \_/   
    ----------------------------------------------
    The Greatest Programming Language in the World

The one and only programming language that you'll ever need. It solves every single programming dispute, in the most sensible way possible.


Build and Run

You'll need cmake, bison and flex installed to build this project. Source files have the highly contended '.tgplitw' extension.

mkdir build && cd build
cmake .. && make
./tgplitw ../examples/helloworld.tgplitw

Hello world

The first thing to note about this program, is that all code is followed by a C style comment. Anything that's not, is treated as a comment. That means this very readme file is executable, so give it a go! It encourages documentation, as all sources files are just documents with code in. As everyone knows it's far better to describe how code works in comments then to express it in the code its self.

Every statement is expressed as a 'pipeline'. They work very similar to unix shell pipes. However, they always start with an expression and end with a variable to store the result into. You can also put /dev/null to discard the output value (obviously).

// "Hello, World!" -> print -> /dev/null

Headers

All source files have to be wrapped in a header block. It has three sections, each one separated by a line of 's. The first contains a list of attributes. Any number of these can be included, but a name, date and mood at time of writing the file.

The second as a description of the files content, and finally the code itself.

Name: BenJilks
Date: Sunday the 22nd of August 2021
Mood: good
-------------------------
Readme
-------------------------

...

_________________________

Numbers

Numbers are very important in this language, as numbers and variables are the same thing. All numbers are expressed in base64, where negative and decimals are allowed and _, & as the extra 2 digits. This means all variable names can be written as a number. Assigning will change the value of that number from it's literal to a new value.

The advantages of this system are obvious. Fortran did it, so it must be good right?

// "Literal: " -> print -> /dev/null
// -aa.1 -> print -> /dev/null
result is -650.016

// "\nAssignment: " -> print -> /dev/null
// 2 -> 1
// 1 + 1 -> print -> /dev/null
result is 4

change 1 back to being 1
// 3 - 2 -> 1

Arrays

The age old debate, the eternal question, should arrays start at 0 or 1? The real solution is neither of them, arrays should always start in the middle.

There's also the question of trailing commas. What about proceeding commas? That's what I've used.

// "\nArrays: " -> print -> /dev/null
// [,1 ,2 ,3] -> x
// [,x[0] ,x[-1] ,x[1]] -> print -> /dev/null
result is [2, 1, 3]

Functions

I read somewhere that functions should only have one or two arguments, so all functions only have one. It's also good to restrict types you can pass into a function, so you specify what types can't be passed in and returned. The function below can't have a None type passed in or returned from it.

The variables (/numbers) in and out allow you to access function inputs and outputs.

As manners are important, you have to ask the interpreter to make a function with please and ending it with thanks. Making functions is a lot of work, so encouragement is needed.

// please define none -> square -> none
// {
        // in * in -> out
// } thanks

// "\nFunctions: " -> print -> /dev/null
// 5 -> square -> print -> /dev/null
result is 25

Pipelines

Almost anything can be done in a pipeline, using the special pipes. The first being match, I heard that this pattern matching is the new thing. So I decided to make all conditionals with it. I'm pretty sure they're just fancy if else statements right? Anyways, it takes the input and picks the first condition that isn't true.

The corresponding block is executed with in as the match statements input and out being sent to the pipeline output.

// "Enter number: " -> input -> to_int -> match
// {
        // >5: { "a" -> out }
        // =None: { "b" -> out }
// } -> print -> /dev/null

The other is eval, this just executes the following expression and parses in as the pipeline input.

// "\nEval: " -> print -> /dev/null
// 5 -> square -> eval in + 1 -> print -> /dev/null
result is 26

Tee

A commonly used pattern is tee, this allows you to save a value in the middle of a pipeline.

// "\nTee: " -> print -> /dev/null
// [,b ,"x"] -> tee -> y
// [,x ,y] -> print -> /dev/null
result is [11, 11]

Standard Library

Here are all the functions in the standard library

Function Name Description Input Output
print Prints input on line value None
input Print input as prompt and ask user input prompt inputted
tee Tee off the input [value, out] value
len Length of input array length
right Everything to the right of the index [arr, index] arr
left Everything to the left of the index [arr, index] arr
remove Everything except the value at index [arr, index] arr
random Generate random value None random
sleep Sleeps for x amount of seconds time None

Some Examples

Just a few example scripts. All of these are also included as separate files under 'examples'.

Sum

There are no loops in TGPLITW, so recursion is the way to go!

// please define none -> sum -> none
// {
        // [,in ,"arr"] -> tee -> len -> eval in + [,"arr_len"] -> tee -> match
        // {
                // =1: { [,arr ,0] -> remove -> sum -> eval arr[0] + in -> out }
                // =None: { arr[0] -> out }
        // } -> out
// } thanks

// "\nSum: " -> print -> /dev/null
// [,1 ,2 ,3] -> sum -> print -> /dev/null

Seq

// please define none -> seq -> none
// {
        // [,in ,"count"] -> tee -> match
        // {
                // =0: { count - 1 -> seq -> eval in + [,count] -> out }
                // =None: { [,count] -> out }
        // } -> out
// } thanks

// "\nSeq: " -> print -> /dev/null
// a -> seq -> print -> /dev/null
// a -> seq -> len -> print -> /dev/null
// a -> seq -> sum -> print -> /dev/null

Shuffle

As arrays are index from the middle, moving all middle element to the front makes 
for an interesting shuffle function.

// please define none -> shuffle -> none
// {
        // [,in ,"arr"] -> tee -> len -> match
        // {
                // =1: { [,arr ,0] -> remove -> shuffle -> eval arr[0] + in -> out }
                // =None: { [,arr[0]] -> out }
        // } -> out
// } thanks

// "\nShuffle: " -> print -> /dev/null
// a -> seq -> shuffle -> shuffle -> print -> /dev/null

Map

Functions can be used as normal objects, so a map function like this is possible.

// please define none -> map -> none
// {
        // in[-1] -> func
        // in[0] -> arr

        // arr -> len -> eval 0 - in / 2 -> index
        // arr[index] -> func -> value

        // arr -> len -> match
        // {
                // =1:
                // { 
                        // [,arr ,index] -> remove -> rest
                        // [,func ,rest] -> map -> eval [,value] + in -> out
                // }
                // =None: { [,value] -> out }
        // } -> out
// } thanks

// "\nMap: " -> print -> /dev/null
// a -> seq -> eval [,square ,in] -> map -> print -> /dev/null

Nested

Functions can also be nested inside other function. Everything is scoped.

// please define none -> nested -> none
// {
        // please define none -> test -> none
        // {
                // in + 1 -> out
        // } thanks
        // in -> test -> out
// } thanks

// "\nNested: " -> print -> /dev/null
// a -> nested -> print -> /dev/null

Binary Search

As arrays start from the middle, we can use this to make a binary search with

// please define none -> search -> none
// {
        // in[-1] -> arr
        // in[0] -> key

        // arr[0][-1] -> match
        // {
                // >=key: { [,arr ,0] -> right -> eval [,in ,key] -> search -> out }
                // <=key: { [,arr ,0] -> left -> eval [,in ,key] -> search -> out }
                // =None: { arr[0][0] -> out }
        // } -> out
// } thanks

Define some test data
// [
        // ,[,4 ,"a"]
        // ,[,6 ,"b"]
        // ,[,7 ,"c"]
        // ,[,a ,"d"]
        // ,[,G ,"e"]
// ] -> x

Run a search
// "\nBinary Search:" -> print -> /dev/null
// [,x ,G] -> search -> print -> /dev/null